package cn.zhx.domain.strategy.service.rule.tree.factory.engine;

import cn.zhx.domain.strategy.model.valobj.RuleLogicCheckTypeVO;
import cn.zhx.domain.strategy.model.valobj.RuleTreeNodeLineVO;
import cn.zhx.domain.strategy.model.valobj.RuleTreeNodeVO;
import cn.zhx.domain.strategy.model.valobj.RuleTreeVO;
import cn.zhx.domain.strategy.service.rule.tree.ILogicTreeNode;
import cn.zhx.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Author: zhx
 * @Date: 2024/07/05
 * @Description: 决策树引擎
 **/
@Slf4j
public class DecisionTreeEngine implements IDecisionTreeEngine{

    private final Map<String, ILogicTreeNode> logicTreeNodeGroup;

    private final RuleTreeVO ruleTreeVO;

    public DecisionTreeEngine(Map<String, ILogicTreeNode> logicTreeNodeGroup, RuleTreeVO ruleTreeVO) {
        this.logicTreeNodeGroup = logicTreeNodeGroup;
        this.ruleTreeVO = ruleTreeVO;
    }

    /**
     * 根据用户ID、策略ID和奖惩ID处理策略奖惩数据。
     *
     * @param userId 用户ID。
     * @param strategyId 策略ID。
     * @param awardId 奖惩ID。
     * @return 返回处理后的策略奖惩数据。
     */
    @Override
    public DefaultTreeFactory.StrategyAwardVO process(String userId, Long strategyId, Integer awardId, Date endDateTime) {
        DefaultTreeFactory.StrategyAwardVO strategyAwardData = null;

        // 获取规则树的根节点和节点映射
        //获取基础信息
        String nextNode = ruleTreeVO.getTreeRootRuleNode(); //rule_lock
        Map<String, RuleTreeNodeVO> treeNodeMap = ruleTreeVO.getTreeNodeMap();

        // 从根节点开始遍历规则树
        // 获取起始节点「根节点记录了第一个要执行的规则」
        RuleTreeNodeVO ruleTreeNode = treeNodeMap.get(nextNode);
        while (null != nextNode) {
            // 根据当前节点的规则键获取逻辑节点
            // 获取决策节点
            ILogicTreeNode logicTreeNode = logicTreeNodeGroup.get(ruleTreeNode.getRuleKey());
            // 获取规则值
            String ruleValue = ruleTreeNode.getRuleValue();

            // 执行逻辑节点的逻辑计算
            // 决策节点计算
            DefaultTreeFactory.TreeActionEntity logicEntity = logicTreeNode.logic(userId, strategyId, awardId,ruleValue,endDateTime);
            // ALLOW / TAKE_OVER
            RuleLogicCheckTypeVO ruleLogicCheckTypeVO = logicEntity.getRuleLogicCheckType();
            strategyAwardData = logicEntity.getStrategyAwardData();
            log.info("决策树引擎【{}】treeId:{} node:{} code:{} info{}", ruleTreeVO.getTreeName(), ruleTreeVO.getTreeId(), nextNode, ruleLogicCheckTypeVO.getCode(),ruleLogicCheckTypeVO.getInfo());

            // 根据逻辑检查类型确定下一个节点
            // 获取下个节点
            nextNode = nextNode(ruleLogicCheckTypeVO.getCode(), ruleTreeNode.getTreeNodeLineVOList());
            ruleTreeNode = treeNodeMap.get(nextNode);
        }

        // 返回最终的策略奖惩数据
        // 返回最终结果
        return strategyAwardData;
    }

    /**
     * 根据当前事务值和规则线列表确定下一个节点。
     * 该方法通过遍历规则线列表，使用决策逻辑来判断当前事务值是否满足某条规则线的条件。
     * 如果找到满足条件的规则线，则返回该规则线指向的下一个节点的ID。
     * 如果列表为空或不存在满足条件的规则线，则抛出运行时异常。
     *
     * @param matterValue 当前值。 0000-放行 0001-接管
     * @param treeNodeLineVOList 规则线列表。
     * @return 返回下一个节点的ID，如果不存在则返回null。
     */
    public String nextNode(String matterValue, List<RuleTreeNodeLineVO> treeNodeLineVOList) {
        // 如果规则线列表为空或为null，则直接返回null
        if (null == treeNodeLineVOList || treeNodeLineVOList.isEmpty()) return null;

        // 决策树：
        //                rule_lock
        //        rule_stock     rule_lucky
        //   rule_lucky   end   end       end
        // 遍历规则线列表，寻找满足条件的规则线,两条选一条
        for (RuleTreeNodeLineVO nodeLine : treeNodeLineVOList) {
            // 使用决策逻辑判断当前事务值是否满足规则线的条件
            if (decisionLogic(matterValue, nodeLine)) {
                // 如果满足条件，则返回该规则线指向的下一个节点的ID
                return nodeLine.getRuleNodeTo();
            }
        }
        // 如果遍历完所有规则线仍未找到满足条件的，则返回空
        return null;
    }


    /**
     * 根据当前值和规则限制类型判断是否满足条件。
     *
     * @param matterValue 当前值。
     * @param nodeLine 规则线。
     * @return 如果满足条件返回true，否则返回false。
     */
    public boolean decisionLogic(String matterValue, RuleTreeNodeLineVO nodeLine) {
        switch (nodeLine.getRuleLimitType()) {
            case EQUAL:
                return matterValue.equals(nodeLine.getRuleLimitValue().getCode());
            // 以下规则暂时不需要实现
            case GT:
            case LT:
            case GE:
            case LE:
            default:
                return false;
        }
    }


}
